用 Long 做 Map 的 Key,存的对象花一下午才取出来,坑惨了 您所在的位置:网站首页 java map key类型为integer报错 用 Long 做 Map 的 Key,存的对象花一下午才取出来,坑惨了

用 Long 做 Map 的 Key,存的对象花一下午才取出来,坑惨了

2024-07-17 06:58| 来源: 网络整理| 查看: 265

大家好,我是一航!

事情是这样!某天中午午休完,正在开始下午的搬砖任务,突然群里面热闹起来,由于忙,也就没有去看,过了一会儿,突然有伙伴在群里@我,就去爬楼看了一下大家的聊天记录,结果是发现了一个很有意思的Bug;看似很基础Map的取值问题,对于基础不是特别扎实的朋友来说,但如果真的遇到,可能会被坑惨,群里这位老弟就被坑了一下午,在这里分享给大家。

讨论的起因是一个老弟问了这样一个问题:

简单一句话表述就是:接口回了个Map,key是Long型的,Map中有数据,可取不到值;

由于基础数据类型的Key在以Json返回的时候,都被转成了String,有伙伴儿很快提出确认Key是不是被转成了String,结果都被否认了;但对于这个否认,我是持有怀疑态度的,所以,这里得必须亲自验证一下;

问题梳理

为了搞清楚状况,需要先简单的梳理一下;

业务场景是这样:

A服务提供了一个接口,返回了一个Map B服务通过RestTemplate调用A服务对应的接口,入参就就是一个Long B服务通过得到Map响应之后,再通过Long值作为Key,去得到Object

问题点:

至于这种接口设计方式是否合理,文末另说,这位老弟遇到的问题是:B服务能正常接收到Map对象,也就是log.info("map:{}",map)都能正常输出对应的key和Object;但是通过map.get(sourceId)取Object,有时候正常,有时候取出来的null;这一下子就变的有意思了;程序员遇到Bug,只要是必现或者能百度到的,那都不算bug,轻轻松松拿下;唯独那种时而出现时而正常的bug,是最头疼的,可能让你一度怀疑人生;

复现Bug

为了能把这个问题点说清楚,按他的写法,我模拟了一下他的业务逻辑,写了一段简单代码复现一下正常情况和异常情况:

能正常取值

key为Long l = 123456789000L;,代码如下:

@Slf4j public class Main { public static void main(String[] args) throws Exception { //A服务的数据 Map mp = new HashMap(); Long l = 123456789000L; mp.put(l,"123"); log.info("key:{}",l); // B服务通过网络请求得到A服务的响应文本 String s1 = JSON.toJSONString(mp); log.info("json文本:{}",s1); // 将文本转换成Map对象 Map mp2 = JSON.parseObject(s1,Map.class); log.info("json文本转换的Map对象:{}",mp2); // 通过key取值 log.info("通过key:{}得到的值:{}",l,mp2.get(l)); } }

运行结果

取值为null

异常情况下唯一的区别是key换成了Long l = 123456789L;

public class Main { public static void main(String[] args) throws Exception { //A服务的数据 Map mp = new HashMap(); Long l = 123456789L; mp.put(l,"123"); // B服务通过网络请求得到A服务的响应文本 String s1 = JSON.toJSONString(mp); log.info("json文本:{}",s1); // 将文本转换成Map对象 Map mp2 = JSON.parseObject(s1,Map.class); log.info("json文本转换的Map对象:{}",mp2); // 通过key取值 log.info("通过key:{}得到的值:{}",l,mp2.get(l)); } }

运行结果

结果分析

发现没有!两段代码,除了key不一样,逻辑部分没有任何区别,均无报错,且都能正常运行,那为何一段正常一段结果为null呢?

bug场景复现了,一切就别的简单多了,既然mp2.get(l)取的值不同,问题点也肯定就出现在这个附近了,debug去分析一下mp2里面到底放了些啥:

好家伙!事出反常必有妖;

一看这两种情况下mp2对应key的类型(上图箭头部分),应该就明白,为什么key是long l = 123456789l的时候,mp2取不到值了吧;因为转换后mp2里面存的压根儿就不是Long型的key,而是一个Integer的key?当Key是Long型的时候,就能正常取到值,当为Integer的时候,取出来的就是null

为什么变成了Integer

明明我存的是一个Long作为key,Json文本转mp2的时候我也是通过Map去接收,似乎一切都有理有据,为什么最后mp2的key一会儿是Integer,一会儿是Long呢?

毕竟核心代码只有这么简单的5行,稍作分析就能知道,问题点是出在这行代码

Map mp2 = JSON.parseObject(s1,Map.class);

类型转换传递的对象仅仅是一个Map.class;并没有指明Map中的key和value的具体类型是什么;因为泛型擦除,导致fastJson在遇到基础数字类型key的时候,无法判断其具体的类型,只能通过长度去匹配一个最合适的数据类型;由于123456789可以使用Integer去接收,就将其转换成了Integer;而123456789000就只能通过Long型接收,就转换成了Long型;

以下是fastJson源码中关于数字类型判断的一段代码;用来匹配当前的数字需要转换成什么类型逻辑判断:

if (negative) { if (i > this.np + 1) { if (result >= -2147483648L && type != 76) { if (type == 83) { return (short)((int)result); } else if (type == 66) { return (byte)((int)result); } else { return (int)result; } } else { return result; } } else { throw new NumberFormatException(this.numberString()); } } else { result = -result; if (result


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有